package edu.hawaii.halealohacli.command;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.client.BadXmlException;
import org.wattdepot.client.MiscClientException;
import org.wattdepot.client.NotAuthorizedException;
import org.wattdepot.client.ResourceNotFoundException;
import org.wattdepot.client.WattDepotClient;

/**
 * Ranks the towers of the energy source.
 * 
 * @author Group BackR
 * 
 */
public class RankTowers implements Command {

  private String command = "rank-towers";
  private String arguments = "[start] [end]";
  private int numParams = 2;
  private String help =
      "Returns a list in sorted order from least to most energy consumed between "
          + "the [start] and [end] date (yyyy-mm-dd).";
  private String[] towers = { "Ilima", "Mokihana", "Lehua", "Lokelani" };

  @Override
  public String run(String[] input, WattDepotClient client) {
    String output = "\"" + input[1] + "\" is not a valid source.";
    // Variable to determine with argument date the program is checking.
    int check = 1;
    try {

      // Create a date format to check the date of the second argument.
      String formatString = "yyyy-MM-dd";
      SimpleDateFormat format = new SimpleDateFormat(formatString, Locale.US);
      format.setLenient(false);
      // Check if first argument is a valid date.
      Date date1 = format.parse(input[1]);
      // Set check to 2. Checking second date.
      check = 2;
      // Check if second argument is a valid date.
      Date date2 = format.parse(input[2]);
      // New date format to include in the output.
      SimpleDateFormat checkTime = new SimpleDateFormat("MMM-dd-yyyy", Locale.US);
      GregorianCalendar gc1 = new GregorianCalendar();
      GregorianCalendar gc2 = new GregorianCalendar();
      DatatypeFactory dtf = DatatypeFactory.newInstance();
      XMLGregorianCalendar today = dtf.newXMLGregorianCalendar(gc1);
      // Set the date to the user input.
      gc1.setTime(date1);
      // Set the date to the user input.
      gc2.setTime(date2);
      // Create the specified day start.
      XMLGregorianCalendar specifiedDayStart = dtf.newXMLGregorianCalendar(gc1);
      // Create the specified day end.
      XMLGregorianCalendar specifiedDayEnd = dtf.newXMLGregorianCalendar(gc2);
      // New date format to include in output if date is a future date.
      SimpleDateFormat futureDate = new SimpleDateFormat("MMM-dd-yyyy", Locale.US);
      // Checks if input date is a future date.
      if (today.compare(specifiedDayStart) < 0) {
        output =
            "You have enetered a future date: " + futureDate.format(gc1.getTime()) + "\n"
                + "It will be impossible to gather the data, don't you think? Try again.";
      }
      else if (today.compare(specifiedDayEnd) < 0) {
        output =
            "You have entered a future date: " + futureDate.format(gc2.getTime()) + "\n"
                + "It will be impossible to gather the data, don't you think? Try again.";
      }
      // Check if given dates are the same.
      else if (specifiedDayStart.equals(specifiedDayEnd)) {
        output = "The given dates are the same. Please try again and enter a date range.";
      }
      // Check if the given end date is before the given start date.
      else if (specifiedDayEnd.compare(specifiedDayStart) < 0) {
        output =
            "The given end date: \"" + input[2] + "\" is before the given start date: \""
                + input[1] + "\"." + " Please try again and enter a correct date range.";
      }
      else {
        // Set time to zero.
        specifiedDayStart.setTime(0, 0, 0, 0);
        SortedSet<Rank> rankTowers = new TreeSet<Rank>();
        for (String towerName : towers) {
          Double energy =
              client.getEnergyConsumed(towerName, specifiedDayStart, specifiedDayEnd, 10);
          Rank tower = new Rank(towerName, energy);
          rankTowers.add(tower);
        }
        StringBuffer buffer = new StringBuffer();
        for (Rank tower : rankTowers) {
          // Cast double data value back to long.
          long data = Math.round(tower.getData());
          // Convert the energy into a string.
          String energy = Long.toString(data / 1000);
          String towerOutput = String.format("%n%-10s  %s kWH", tower.getName(), energy);
          buffer.append(towerOutput);
        }
        output =
            "For the interval " + checkTime.format(gc1.getTime()) + " to "
                + checkTime.format(gc2.getTime()) + ", energy consumption by tower was:"
                + buffer.toString();
      }
    }
    catch (NotAuthorizedException e) {
      return "Unauthorized to access the sever. Try again.";
    }
    catch (BadXmlException e) {
      return "Could not retrieve data for: " + input[1] + " on " + input[2] + "\n"
          + "It might be possible that the date entered is too back in the past. Try again.";
    }
    catch (MiscClientException e) {
      return "Unexpected error. Try again.";
    }
    catch (ResourceNotFoundException e) {
      return input[1] + " does not exist!";
    }
    catch (DatatypeConfigurationException e) {
      return "Could not format date input.";
    }
    catch (ParseException e) {
      return "\"" + input[check] + "\" is not a valid date.";
    }
    catch (IllegalArgumentException e) {
      return "\"" + input[check] + "\" is not a valid date.";
    }
    return output;
  }

  @Override
  public String getCommand() {
    return command;
  }

  @Override
  public int getNumParams() {
    return numParams;
  }

  @Override
  public String getHelp() {
    return command + " " + arguments + "\n" + help;
  }
}
